package plp.orientadaObjetos1.expressao.valor;

import java.util.Collection;
import java.util.HashMap;

import plp.expressions2.memory.VariavelJaDeclaradaException;
import plp.expressions2.memory.VariavelNaoDeclaradaException;
import plp.imperative1.util.Lista;
import plp.orientadaObjetos1.excecao.declaracao.ClasseNaoDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ObjetoNaoDeclaradoException;
import plp.orientadaObjetos1.excecao.execucao.IndiceInexistenteException;
import plp.orientadaObjetos1.expressao.Expressao;
import plp.orientadaObjetos1.expressao.ListaExpressao;
import plp.orientadaObjetos1.memoria.AmbienteCompilacaoOO1;
import plp.orientadaObjetos1.memoria.AmbienteExecucaoOO1;
import plp.orientadaObjetos1.util.Tipo;
import plp.orientadaObjetos1.util.TipoArray;

public class ValorArray implements ValorConcreto {
	
	private HashMap<Integer, Expressao> valor = new HashMap<Integer, Expressao>();

	public ValorArray(HashMap<Integer, Expressao> valor) {
		this.valor = valor;
	}
	
	public ValorArray(ListaExpressao listaExpressao) {
		this.povoarValor(listaExpressao);
	}
	
	public void povoarValor(Lista<Expressao> listaExpressao) {
		if (listaExpressao.getHead() != null) {
			this.addElement(listaExpressao.getHead());
			Lista<Expressao> newExpression = listaExpressao.getTail();
			if (newExpression != null) {
				this.povoarValor(new Lista<Expressao>(newExpression.getHead(), newExpression.getTail()));
			}
		}
	}

	public void addElement(Expressao element) {
		this.valor.put(length(), element);
	}
	
	public int length() {
		return this.valor().keySet().size();
	}
	
	public Expressao get(int ordem) throws IndiceInexistenteException {
		if (ordem > length() - 1) {
			throw new IndiceInexistenteException();
		}
		return this.valor().get(ordem);
	}
	
	@Override
	public Tipo getTipo(AmbienteCompilacaoOO1 ambiente) {
		TipoArray tipo = new TipoArray();
		try {
			tipo.setTipoArray(this.getTipoDoArray(ambiente));
		} catch (VariavelNaoDeclaradaException e) {
			e.printStackTrace();
		} catch (ClasseNaoDeclaradaException e) {
			e.printStackTrace();
		}
		return tipo;
	}

	public Tipo getTipoDoArray(AmbienteCompilacaoOO1 ambiente) throws VariavelNaoDeclaradaException, ClasseNaoDeclaradaException {
		Collection<Expressao> values = this.valor().values();
		for (Expressao expressao : values) {
			return expressao.getTipo(ambiente);
		}
		return null;
	}

	@Override
	public Valor avaliar(AmbienteExecucaoOO1 ambiente) throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException, ObjetoNaoDeclaradoException, ClasseNaoDeclaradaException {
		return this;
	}

	@Override
	public boolean checaTipo(AmbienteCompilacaoOO1 ambiente) throws VariavelNaoDeclaradaException, ClasseNaoDeclaradaException {
		boolean result = false;
		for (Expressao exp : this.valor.values()) {
			if (exp.checaTipo(ambiente)) {
				result = true;
			}
		}
		return result;
	}

	@Override
	public boolean equals(ValorConcreto valor) {
		return false;
	}

	public HashMap<Integer, Expressao> valor() {
		return this.valor;
	}
	
	
}
